package cate.game.role.bag.kitchenware;

import cate.common.table.d.GDObj;
import cate.common.table.item.kitchenware.row.KitchenwareAttrRow;
import cate.common.table.item.kitchenware.row.KitchenwareBaseRow;
import cate.common.table.item.kitchenware.row.KitchenwareLevelUpRow;
import cate.common.table.item.kitchenware.row.KitchenwareSkillRow;
import cate.game.GameBody;
import cate.game.attr.FightAttr;
import cate.game.play.support.PlayBuildContext;
import cate.game.role.Role;
import cate.game.role.bag.item.BaseBagItem;
import com.fasterxml.jackson.annotation.JsonIgnore;
import cp.solution.pattern.ICopiable;
import cp.solution.util.collection.ListKit;
import easy.java.dev.note.NoteClass;
import easy.java.dev.note.NoteField;

import java.util.*;

@NoteClass("厨具数据 ")
public class Kitchenware extends BaseBagItem implements ICopiable<Kitchenware> {
    @NoteField("历史最高等级")
    public int maxLevel;

    @NoteField("等级")
    public int level;

    @NoteField(value = "基础属性id们")
    public List<Integer> attrIds;

    @NoteField(value = "技能id们")
    public List<Integer> skillIds;

    @NoteField(value = "厨具重铸技能、属性的缓存")
    public KitchenwareReCastTemp reCast;

    public Kitchenware() {
    }

    public Kitchenware(Role role, int tid, long num) {
        super(role, GDObj.Type.KITCHENWARE, tid, num);
        this.attrIds = genAttrs(role.getGame());
        this.skillIds = genSkills(role.getGame());
        reCast = new KitchenwareReCastTemp();
        reCast.initialize();
        initialize(role);
    }

    @Override
    public void initialize(Role role) {
        super.initialize(role);
        if (attrIds == null) {
            attrIds = new ArrayList<>();
        }
        if (skillIds == null) {
            skillIds = new ArrayList<>();
        }
        if (reCast == null) {
            reCast = new KitchenwareReCastTemp();
        }
        reCast.initialize();
    }

    private List<Integer> genAttrs(GameBody game) {
        List<Integer> attrIds = new ArrayList<>();
        KitchenwareLevelUpRow levelUpRow = findMaxLevelUpRow(game);
        if (levelUpRow != null) {
            List<Integer> excludes = new ArrayList<>();
            for (Integer attrGrouId : levelUpRow.attrGroup) {
                KitchenwareAttrRow attrRow = game.table.kitchenware.attr.randomGroupRow(attrGrouId, excludes);
                if (attrRow != null) {
                    attrIds.add(attrRow.id);
                    excludes.add(attrRow.protoId);
                }
            }
        }
        return attrIds;
    }

    public void recastAttrs(GameBody game) {
        List<Integer> newAttrIds = genAttrs(game);
        reCast.attrIds = newAttrIds;
        if (attrIds.containsAll(newAttrIds)) {
            int lastAttrId = newAttrIds.get(newAttrIds.size() - 1);
            int lastProto = game.table.kitchenware.attr.get(lastAttrId).protoId;
            KitchenwareLevelUpRow levelUpRow = findMaxLevelUpRow(game);
            int lastGroup = levelUpRow.attrGroup.get(levelUpRow.attrGroup.size() - 1);
            KitchenwareAttrRow attrRow = game.table.kitchenware.attr.randomGroupRow(lastGroup, Collections.singletonList(lastProto));
            if (attrRow != null) {
                reCast.attrIds.set(newAttrIds.size() - 1, attrRow.id);
            }
        }
    }

    public void recastSkill(GameBody game) {
        List<Integer> newSkills = genSkills(game);
        reCast.skillIds = newSkills;
        if (skillIds.containsAll(newSkills)) {
            KitchenwareBaseRow baseRow = getTpl(game);
            int lastSkillId = newSkills.get(newSkills.size() - 1);
            int lastProto = game.table.kitchenware.skill.get(lastSkillId).skillProtoId;
            KitchenwareSkillRow skillRow = game.table.kitchenware.skill.randomSkill(baseRow.skillGroup.get(baseRow.skillGroup.size() - 1), Collections.singletonList(lastProto));
            if (skillRow != null) {
                reCast.skillIds.set(newSkills.size() - 1, skillRow.id);
            }
        }
    }

    private List<Integer> genSkills(GameBody game) {
        List<Integer> skills = new ArrayList<>();
        KitchenwareBaseRow baseRow = getTpl(game);
        if (baseRow != null) {
            for (int group : baseRow.skillGroup) {
                KitchenwareSkillRow skillRow = role.getGame().table.kitchenware.skill.randomSkill(group);
                if (skillRow != null) {
                    skills.add(skillRow.id);
                }
            }
        }
        return skills;
    }

    public KitchenwareLevelUpRow findMaxLevelUpRow(GameBody game) {
        return game.table.kitchenware.levelUp.findRow(tid, maxLevel);
    }

    public KitchenwareLevelUpRow findLevelUpRow(GameBody game) {
        return game.table.kitchenware.levelUp.findRow(tid, level);
    }

    @Override
    public KitchenwareBaseRow getTpl(PlayBuildContext ctx) {
        return ctx.kitchenwareExcel().base.get(tid);
    }

    @Override
    public KitchenwareBaseRow getTpl(GameBody game) {
        return game.table.kitchenware.base.get(tid);
    }

    /**
     * 升级属性
     */
    private void levelUpAttr(GameBody game) {
        if (attrIds == null || attrIds.isEmpty()) {
            return;
        }
        Map<Integer, Integer> oldGroupAttrs = new HashMap<>();
        Set<Integer> protos = new HashSet<>();
        for (Integer attr : attrIds) {
            KitchenwareAttrRow row = game.table.kitchenware.attr.get(attr);
            if (row != null) {
                protos.add(row.protoId);
                oldGroupAttrs.put(row.attrGroup, row.id);
            }
        }
        attrIds.clear();
        KitchenwareLevelUpRow levelUpRow = findMaxLevelUpRow(game);
        if (levelUpRow != null) {
            for (Integer group : levelUpRow.attrGroup) {
                if (oldGroupAttrs.containsKey(group)) {
                    attrIds.add(oldGroupAttrs.get(group));
                    continue;
                }
                boolean hasProto = false;
                for (Integer proto : protos) {
                    KitchenwareAttrRow attrRow = game.table.kitchenware.attr.getAttr(group, proto);
                    if (attrRow != null) {
                        attrIds.add(attrRow.id);
                        hasProto = true;
                    }
                }
                if (!hasProto) {
                    KitchenwareAttrRow attrRow = game.table.kitchenware.attr.randomGroupRow(group, Collections.emptyList());
                    if (attrRow != null) {
                        attrIds.add(attrRow.id);
                    }
                }
            }
        }
    }

    /**
     * 升级技能
     */
    private void levelUpSkill(GameBody game) {
        if (skillIds == null || skillIds.isEmpty()) {
            return;
        }
        // 找一个等级最低的技能进行升级
        int toLevelUpProto = 0;
        int toLevelUpLevel = 0;
        int toLevelUpIdx = 0;
        for (int i = 0; i < skillIds.size(); ++i) {
            int skillTid = skillIds.get(i);
            KitchenwareSkillRow skillRow = game.table.kitchenware.skill.get(skillTid);
            if (skillRow != null && skillRow.level > toLevelUpLevel) {
                toLevelUpProto = skillRow.skillProtoId;
                toLevelUpLevel = skillRow.level;
                toLevelUpIdx = i;
            }
        }
        if (toLevelUpProto > 0) {
            KitchenwareBaseRow baseRow = getTpl(game);
            if (baseRow != null) {
                KitchenwareSkillRow breakSkillRow = game.table.kitchenware.skill.findGroupProtoRow(baseRow.skillGroup.get(toLevelUpIdx), toLevelUpProto);
                if (breakSkillRow != null) {
                    skillIds.set(toLevelUpIdx, breakSkillRow.id);
                }
            }
        }
    }

    @Override
    public Kitchenware copy() {
        Kitchenware cp = new Kitchenware();
        super.copy(cp);
        cp.level = this.level;
        cp.maxLevel = this.maxLevel;
        cp.reCast = this.reCast != null ? this.reCast.copy() : null;
        cp.attrIds = ListKit.cloneList(this.attrIds, Integer::intValue);
        cp.skillIds = ListKit.cloneList(this.skillIds, Integer::intValue);
        return cp;
    }

    public void levelUp(GameBody game) {
        level += 1;
        if (level > maxLevel) {
            maxLevel = level;
            levelUpAttr(game);
        }
        this.reCast.clear();
    }

    public void levelLose(int level) {
        if (this.level > level) {
            this.level -= level;
        } else {
            this.level = 0;
        }
    }

    public void breakUp(GameBody gameBody, int breakTid) {
        tid = breakTid;
        levelUpSkill(gameBody);
        levelUpAttr(gameBody);
        this.reCast.clear();
    }

    @JsonIgnore
    public FightAttr getPowerAttr(PlayBuildContext ctx) {
        FightAttr attr = new FightAttr();
        if (attrIds != null && !attrIds.isEmpty()) {
            for (int attrId : attrIds) {
                attr.add(new FightAttr(ctx.kitchenwareExcel().attr.get(attrId).attrStr));
            }
        }
        return attr;
    }

    /**
     * 保存缓存
     */
    public void saveTempSkill() {
        if (!reCast.skillIds.isEmpty()) {
            skillIds.clear();
            skillIds.addAll(reCast.skillIds);
            reCast.skillIds.clear();
        }
    }

    /**
     * 保存缓存
     */
    public void saveTempAttr() {
        if (!reCast.attrIds.isEmpty()) {
            attrIds.clear();
            attrIds.addAll(reCast.attrIds);
            reCast.attrIds.clear();
        }
    }
}
